package com.spring.nio.business.user.service.impl;

import com.google.common.collect.Lists;
import com.spring.nio.business.user.constant.UserStatusEnum;
import com.spring.nio.business.user.dto.UserDTO;
import com.spring.nio.business.user.mapper.UserRepository;
import com.spring.nio.business.user.param.UserCreateParam;
import com.spring.nio.business.user.param.UserQueryParam;
import com.spring.nio.business.user.param.UserUpdateParam;
import com.spring.nio.business.user.repository.dataobject.UserDo;
import com.spring.nio.business.user.repository.param.UserDalQueryParam;
import com.spring.nio.business.user.service.UserService;
import com.spring.nio.common.BasicConstant;
import com.spring.nio.core.configuration.NioServerBootstrap;
import com.spring.nio.core.server.FileSystemServer;
import com.spring.nio.core.startup.BasicServer;
import com.spring.nio.util.LocalTime;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务
 * @author spring
 * */

@Slf4j
@Service
@SuppressWarnings("all")
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("userRepository")
    private UserRepository userRepository;

    @Override
    public UserDTO getUserByName(UserQueryParam userQueryParam) {
        try {
            UserDalQueryParam userDalQueryParam = new UserDalQueryParam();
            userDalQueryParam.setUserName(userQueryParam.getUserName());
            UserDo userDo = this.userRepository.query(userDalQueryParam).get(0);
            return this.doToDto(userDo);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    @Override
    public List<UserDTO> getFuzzyQueryUserByName(UserQueryParam userQueryParam) {
        List<UserDTO> userDtos = Lists.newArrayList();
        try {
            UserDalQueryParam userDalQueryParam = new UserDalQueryParam();
            userDalQueryParam.setUserName(userQueryParam.getUserName());
            List<UserDo> list = this.userRepository.getUserByName(userDalQueryParam);
            if (!CollectionUtils.isEmpty(list)) {
                list.stream().forEach(userDo -> {
                    userDtos.add(this.doToDto(userDo));
                });

                return userDtos;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return Lists.newArrayList();
    }

    @Override
    public UserDTO create(UserCreateParam param) {
        UserDo userDo = this.createParamToDo(param);
        this.userRepository.insertSelective(userDo);
        return this.doToDto(userDo);
    }

    @Override
    public void update(UserUpdateParam param) {
        UserDo userDo = this.updateParamToDo(param);
        this.userRepository.updateSelective(userDo);
    }

    @Override
    public void offlineUser(String remoteAddress, Boolean isLogout, Boolean isClearSingleFileUploadTask, Boolean isClearSingleFileDownloadTask) {
        // 1、isLogout为true则使用remove方法移除用户，否则为获取用户
        UserDTO userDto = isLogout?UserService.onlineUser.remove(remoteAddress):UserService.onlineUser.get(remoteAddress);

        // 2、更新数据库用户状态为登出
        if(Optional.ofNullable(userDto).isPresent() && isLogout) {
            UserUpdateParam userUpdateParam = new UserUpdateParam();
            userUpdateParam.setId(userDto.getId());
            userUpdateParam.setStatus(UserStatusEnum.OFFLINE.getStatus());
            NioServerBootstrap.getConfig().getClassPathXmlApplicationContext().getBean(UserService.class).update(userUpdateParam);
            System.out.println("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] NioServerContext | --> 用户 "+userDto.getUserName()+" 下线成功, 剩余用户数 ["+ UserService.onlineUser.size()+"], remoteAddress = ["+remoteAddress+"], thread = ["+Thread.currentThread().getName()+"]");
        }

        // 3、清除文件上传下载任务
        FileSystemServer.finishFileTransportTask(remoteAddress, userDto, isClearSingleFileUploadTask, isClearSingleFileDownloadTask);
    }

    @Override
    public UserDTO getOnlineUserByName(UserQueryParam param) {
        Map userMap = UserService.onlineUser;
        Map<String, List<UserDTO>> onlineUserMap = (new ArrayList<UserDTO>(userMap.values())).stream().collect(Collectors.groupingBy(UserDTO::getUserName));
        if(onlineUserMap.containsKey(param.getUserName())) {
            return ((UserDTO) (((List<UserDTO>) onlineUserMap.get(param.getUserName())).get(0)));
        }
        return null;
    }

    @Override
    public UserDTO getOnlineUserById(UserQueryParam param) {
        Map userMap = UserService.onlineUser;
        Map<Long, List<UserDTO>> onlineUserMap = (new ArrayList<UserDTO>(userMap.values())).stream().collect(Collectors.groupingBy(UserDTO::getId));
        if(onlineUserMap.containsKey(param.getUserId())) {
            return ((UserDTO) (((List<UserDTO>) onlineUserMap.get(param.getUserId())).get(0)));
        }
        return null;
    }

    private UserDo createParamToDo(UserCreateParam param) {
        UserDo userDo = new UserDo();
        userDo.setUserName(param.getUserName());
        userDo.setPassword(param.getPassword());
        userDo.setPhone(param.getPhone());
        userDo.setMail(param.getMail());
        userDo.setLastLoginDate(param.getLastLoginDate());
        userDo.setRegisterDate(param.getRegisterDate());
        userDo.setRegister(param.getRegister());
        userDo.setStatus(param.getStatus());
        userDo.setGmtCreate(param.getRegisterDate());
        userDo.setGmtModified(param.getRegisterDate());
        userDo.setDelTime(param.getRegisterDate());
        return userDo;
    }

    private UserDo updateParamToDo(UserUpdateParam param) {
        UserDo userDo = new UserDo();
        userDo.setId(param.getId());
        userDo.setUserName(param.getUserName());
        userDo.setPassword(param.getPassword());
        userDo.setPhone(param.getPhone());
        userDo.setMail(param.getMail());
        userDo.setLastLoginDate(param.getLastLoginDate());
        userDo.setRegisterDate(param.getRegisterDate());
        userDo.setRegister(param.getRegister());
        userDo.setStatus(param.getStatus());
        userDo.setGmtModified(param.getLastLoginDate() == null?new Date():param.getLastLoginDate());
        return userDo;
    }

    private UserDTO doToDto(UserDo userDo) {
        UserDTO userDto = new UserDTO();
        userDto.setId(userDo.getId());
        userDto.setUserName(userDo.getUserName());
        userDto.setPassword(userDo.getPassword());
        userDto.setLastLoginDate(userDo.getLastLoginDate());
        userDto.setRegisterDate(userDo.getRegisterDate());
        userDto.setRegister(userDo.getStatus());
        userDto.setStatus(userDo.getStatus());
        return userDto;
    }

    public static Map<String, UserDTO> getOnlineUser() {
        return onlineUser;
    }
}
